package topic

import (
	"context"
	"fmt"
	"strconv"

	"mall/common/cachex"
	"mall/common/ctxdatax"
	"mall/common/globalkey"
	"mall/common/resultx"
	"mall/service/backend/common/utils/pointy"
	"mall/service/forum/api/internal/lib/forumreaction"
	"mall/service/forum/api/internal/lib/userrank"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/rpc/forumclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetReplyByIdLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetReplyByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetReplyByIdLogic {
	return &GetReplyByIdLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetReplyByIdLogic) GetReplyById(req *types.ReplyIdReq) (*types.ReplyInfo, error) {
	if req.Id == nil || *req.Id == 0 {
		return nil, resultx.NewErrCode(resultx.FORUM_POST_ID_REQUIRED)
	}

	userId := ctxdatax.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	var preload string = "forumPost:Id,AuthorId,AuthorName,AuthorAvatar,AuthorIp,AuthorLevel,Status,Sticky"
	var eagerLoad string = "forumPost:forumMedia"
	preload += "ContentHtml,CommentStatus,CommentCount,CreatedAt;forumMedia:Id,Uid,Url,Thumbnail,Order"
	var platformId uint32 = globalkey.ThirdPartyPlatformWechatMini

	var searchLogId *uint64
	if req.SearchId != nil && *req.SearchId > 0 {
		searchLogId = pointy.GetPointer(uint64(*req.SearchId))
	}

	res, err := l.svcCtx.ForumRpc.GetPostById(l.ctx, &forumclient.BaseIdReq{
		Id:          req.Id,
		Preload:     pointy.GetPointer(preload),
		EagerLoad:   pointy.GetPointer(eagerLoad),
		VisitorId:   pointy.GetPointer(userId),
		PlatformId:  pointy.GetPointer(platformId),
		SearchLogId: searchLogId,
	})
	if err != nil {
		return nil, err
	}

	if res == nil || res.Id == nil || res.TopicId == nil || *res.Id == 0 || *res.TopicId == 0 {
		return nil, resultx.NewErrCode(resultx.FORUM_POST_STATUS_INVALID)
	}

	// var private bool = true
	// if res.AuthorId != nil && *res.AuthorId > 0 && *res.AuthorId != userId {
	// 	private = false
	// }

	var photos []*types.MediaInfo
	if len(res.Media) > 0 {
		for _, v := range res.Media {
			var url string
			if v.Url != nil && len(*v.Url) > 0 {
				url = *v.Url
			}
			if len(url) == 0 && v.Uri != nil && len(*v.Uri) > 0 {
				url = *v.Uri
			}
			var thumbnail *bool
			if v.Thumbnail != nil {
				thumbnail = pointy.GetPointer(*v.Thumbnail > 0)
			}
			photos = append(photos, &types.MediaInfo{
				Uid:       v.Uid,
				Id:        v.Id,
				Url:       pointy.GetPointer(url),
				Thumbnail: thumbnail,
				AltText:   v.AltText,
				Details:   v.Meta,
				Order:     v.Order,
			})
		}
	}

	var author *types.AuthorInfo
	userRankMap := l.getUserRankMap(userId)
	var levelName *string
	var levelUrl *string
	if userRankMap != nil && res.Author != nil && res.Author.Level != nil && *res.Author.Level > 0 {
		if userRank, ok := userRankMap[*res.Author.Level]; ok {
			levelName = userRank.Name
			levelUrl  = userRank.MediaUrl
		}
	}
	if res.Author != nil && res.Author.Name != nil {
		var anonymous *bool
		if res.Author.Anonymous != nil {
			anonymous = pointy.GetPointer(*res.Author.Anonymous > 0)
		}
		author = &types.AuthorInfo{
			Id:        res.Author.Id,
			Name:      res.Author.Name,
			Avatar:    res.Author.Avatar,
			Ip:        res.Author.Ip,
			Level:     res.Author.Level,
			Anonymous: anonymous,
			LevelName: levelName,
			LevelUrl:  levelUrl,
		}
	}
	var isLiked *bool
	var likeCount *uint64
	flag, count := l.getPostLikeInfo(strconv.FormatInt(int64(*res.Id), 10), strconv.FormatInt(int64(userId), 10))
	isLiked   = pointy.GetPointer(flag)
	likeCount = pointy.GetPointer(uint64(count))
	var statusText *string
	if res.Status != nil {
		statusText = pointy.GetPointer(util.GetStatusText(int32(*res.Status)))
	}
	var commentStatus *bool
	if res.CommentStatus != nil {
		commentStatus = pointy.GetPointer(*res.CommentStatus > 0)
	}
	var createdAt *string
	if res.CreatedAt != nil && len(*res.CreatedAt) > 0 {
		createdAt = pointy.GetPointer(util.GetTimeFromNow(*res.CreatedAt))
	}

	return &types.ReplyInfo{
		Id:            res.Id,
		TopicId:       res.TopicId,
		ContentHtml:   res.ContentHtml,
		Status:        res.Status,
		StatusText:    statusText,
		IsLiked:       isLiked,
		LikeCount:     likeCount,
		CommentStatus: commentStatus,
		CommentCount:  res.CommentCount,
		CreatedAt:     createdAt,
		UpdatedAt:     res.CreatedAt,
		Author:        author,
		Photos:        photos,
	}, nil
}

func (l *GetReplyByIdLogic) getUserRankMap(userId uint64) (map[uint32]*types.UserRankInfo) {
	userRank := userrank.NewUserRank(l.ctx, l.svcCtx)
	userRankList, err := userRank.List(userId)
	if err != nil {
		logrus.Info(fmt.Sprintf("GetReplyById getUserRankMap err: %+v", err))
		return nil
	}

	if len(userRankList) > 0 {
		resp := make(map[uint32]*types.UserRankInfo)
		for _, v := range userRankList {
			if v.Id != nil && *v.Id > 0 {
				resp[uint32(*v.Id)] = v
			}
		}

		return resp
	}

	return nil
}

func (l *GetReplyByIdLogic) getPostLikeInfo(postId string, userId string) (isLiked bool, likeCount int64) {
	forumReaction := forumreaction.NewForumReaction(l.ctx, l.svcCtx, cachex.ForumAnswerLike)
	count, err := forumReaction.Count(postId)
	if err != nil {
		return
	}

	likeCount = count
	if count > 0 && len(userId) > 0 {
		isLiked, err = forumReaction.Done(postId, userId)
	} else if count < 0 {
		likeCount = 0
	}

	return
}
